<html>
    <head>
        <title>模块化总览</title>
    </head>
    <body>
        <script>
            // 模块化总览

                    /*
                        一、导言

                                ABP旨在支持完全模块化的应用程序和系统，其中每个模块都可能具有实体、服务、数据库集成、API、UI组件等。

                                     本文档介绍了模块系统的基础知识。

                                     "模块开发最佳实践指南" 解释了一些最佳实践基于DDD原则和层来开发可重用的应用程序模块。根据本指南设计的模块将独立于数据库，如果需要，可以部署为微服务。

                                     预构建的应用程序模块可以在任何类型的应用程序中使用。

                                     "模块启动模板"  是创建新模块的跨越式方式。

                                     ABP CLI具有支持模块化开发的命令。

                                     所有其他框架功能都与模块化系统兼容。
                    */

                    /*
                        二、模块类  Module Class

                                每个模块都应该定义一个模块类。

                                定义模块类的最简单方法是创建一个从AbpModule派生的类，如下所示：

                                        public class BlogModule : AbpModule
                                        {
                                                    
                                        }

                                1、配置依赖注入和其他模块  Configuring Dependency Injection & Ohter Modules

                                        ①、ConfigureServices 服务配置方法：

                                                ConfigureServices是将你的服务添加到依赖注入系统并配置其他模块的主要方法。
                                                
                                                (这些方法也有异步版本，如果要在这些方法中进行异步调用，请覆盖异步版本而不是同步版本。)

                                                例子：

                                                    public class BlogModule : AbpModule
                                                    {
                                                        // 重写ConfigureServices方法，添加服务到依赖注入系统。
                                                        public override void ConfigureServices(ServiceConfigurationContext context)
                                                        {
                                                            //...
                                                        }
                                                    }

                                                 你可以按照 Microsoft 的文档那样逐个添加服务依赖注册。但是ABP有一个"基于约定的依赖注入系统"，它会自动注册程序集中的所有服务。

                                                 有关依赖注入系统的更多信息，请参阅ABP基本面--依赖注入： https://abp.io/docs/latest/framework/fundamentals/dependency-injection

                                                 你还可以通过这种方式配置其他服务和模块：

                                                 eg：

                                                        public class BlogModule : AbpModule
                                                        {
                                                            public override void ConfigureServices(ServiceConfigurationContext context)
                                                            {
                                                                // 配置数据库连接字符串
                                                                Configure<AbpDbConnectionOptions>(options =>
                                                                {
                                                                    options.ConnectionStrings.Default = "......";
                                                                });
                                                            }
                                                        }

                                                (ConfigureServices方法也有一个异步版本：ConfigureServicesAsync。如果你想在此方法中进行异步调用（使用await关键字），请覆盖异步版本而不是同步版本。如果你同时覆盖异步和同步版本，则只会执行异步版本。)


                                2、Pre & Post Configure Services  前置/后置服务配置
                                
                                                
                                                AbpModule类还定义了PreConfigureServices和PostConfigureServices方法来覆盖和编写你的代码，就在ConfigureServices之前和之后。

                                                请注意，你写入这些方法的代码将在"所有其他模块"的ConfigureServices方法之前/之后执行。
                                                
                                                （这些方法也有异步版本。如果要在这些方法中进行异步调用，请覆盖异步版本而不是同步版本。）


                                3、Application Initialization  应用初始化

                                                    配置完所有模块的所有服务后，应用程序将从初始化所有模块开始。

                                                    在此阶段，你可以解析来自IServiceProvider的服务，因为它已经准备好并且可用。

                                                ①、OnApplicationInitialization方法

                                                        你可以重写OnApplicationInitialization方法以在应用程序启动时执行代码。

                                                        eg:

                                                            public class BlogModule : AbpModule
                                                            {
                                                                public override void OnApplicationInitialization(
                                                                    ApplicationInitializationContext context)
                                                                {
                                                                    var myService = context.ServiceProvider.GetService<MyService>();
                                                                    myService.DoSomething();
                                                                }
                                                            } 
                                                                
                                                        OnApplicationInitialization方法也有一个异步版本。
                                                        
                                                        如果要在此方法中进行异步调用（使用await关键字），请覆盖异步版本而不是同步版本。

                                                        eg:

                                                            public class BlogModule : AbpModule
                                                            {
                                                                public override Task OnApplicationInitializationAsync(
                                                                    ApplicationInitializationContext context)
                                                                {
                                                                    var myService = context.ServiceProvider.GetService<MyService>();
                                                                    await myService.DoSomethingAsync();
                                                                }
                                                            }

                                                        如果你同时覆盖异步和同步版本，则只会执行异步版本。


                                                    ★、OnApplicationInitialization一般由启动模块用来构建ASP.NET核心应用程序的中间件管道。

                                                        eg:
                                                            [DependsOn(typeof(AbpAspNetCoreMvcModule))]  
                                                            public class AppModule : AbpModule
                                                            {
                                                                // 应用初始化钩子，一般用于配置请求管道
                                                                public override void OnApplicationInitialization(ApplicationInitializationContext context)
                                                                {
                                                                    var app = context.GetApplicationBuilder();
                                                                    var env = context.GetEnvironment();

                                                                    if (env.IsDevelopment())
                                                                    {
                                                                        app.UseDeveloperExceptionPage();  
                                                                    }

                                                                    app.UseMvcWithDefaultRoute();
                                                                }
                                                            }

                                                        如果你的模块需要，你还可以执行启动逻辑

                                                ②、Pre & Post Application Initialization 初始化前 和 初始化后  钩子函数

                                                        AbpModule类还定义了OnPreApplicationInitialization和OnPostApplicationInitialization方法来覆盖和写入你的代码，

                                                        就在OnApplicationInitialization之前和之后。

                                                        请注意，你写入这些方法的代码将在所有其他模块的OnApplicationInitialization方法之前/之后执行。

                                                        （这些方法也有异步版本，如果要在这些方法中进行异步调用，请覆盖异步版本而不是同步版本。）

                                
                                4、应用程序关闭  Application Shutdown

                                            最后，如果你想在应用程序关闭时执行一些代码，你可以覆盖OnApplicationShutdown方法。

                                            此方法也有异步版本。如果要在此方法中进行异步调用，请覆盖异步版本而不是同步版本。
                                             
                    */


                    /*
                        三、模块依赖  Module Dependencies

                                    在模块化应用程序中，一个模块依赖于另一个模块并不罕见。

                                    如果ABP模块确实依赖于另一个模块，则它必须声明一个[DependsOn]属性，如下所示：

                                            [DependsOn(typeof(AbpAspNetCoreMvcModule))]
                                            [DependsOn(typeof(AbpAutofacModule))]
                                            public class BlogModule
                                            {
                                                //...
                                            }

                                    你可以使用多个DependsOn属性或将多个模块类型传递给单个DependsOn属性，具体取决于你的偏好。

                                    依赖模块可能依赖于另一个模块，但你只需要定义直接依赖项。

                                    ABP在启动时调查应用程序的依赖关系图，并以正确的顺序初始化/关闭模块。
                    */

                    /*
                        四、添加模块额外程序集  Additional Module Assemblies  

                                    ABP自动将模块的所有服务注册到依赖注入系统。

                                    它通过扫描定义模块类的程序集中的类型来查找服务类型。该程序集被视为模块的主程序集。


                                    通常，每个程序集都包含一个单独的模块类定义。然后模块使用DependsOn属性相互依赖，如上一节所述。

                                    但是，在一些罕见的情况下，你的模块可能由多个程序集组成，其中只有一个程序集定义了一个模块类，并且你希望将其他程序集作为模块的一部分。

                                    在这种情况下，你可以使用AdditionalAssembly属性，如下所示：

                                            [DependsOn(...)] // 正常的模块依赖
                                            [AdditionalAssembly(typeof(BlogService))] // 添加额外的程序集依赖
                                            public class BlogModule
                                            {
                                                //...
                                            }
                                            
                                        在此示例中，我们假设BlogService类位于一个程序集中（csproj），而BlogModule类位于另一个程序集中（csproj）。

                                        使用AdditionalAssembly定义，ABP将加载包含BlogService类的程序集作为博客模块的一部分。

                                        请注意，BlogService只是目标程序集中的任意选定类型。它仅用于指示相关程序集。你可以在程序集中使用任何类型。


                                        （警告：如果你需要使用AdditionalAssembly，请确保你没有以错误的方式设计系统。
                                        
                                                通过上面的示例，BlogService类'程序集通常应该有自己的模块类，并且BlogModule应该使用DependsOn属性依赖于它。
                                                
                                                当你已经可以使用DependsOn属性时，不要使用AdditionalAssembly属性
                                        ）
                    */

                    /*
                        五、框架模块 与  应用模块  (Framework Modules vs Application Modules)

                                    有两种类型的模块。它们没有任何结构差异，但按功能和目的分类：

                                           1、框架模块：这些是框架的核心模块，如缓存、电子邮件、主题化、安全性、序列化、验证、EF Core集成、MongoDB集成…等等。
                                           
                                              它们没有应用程序/业务功能，但通过提供通用基础设施、集成和抽象，使你的日常开发更容易。 


                                           2、应用程序模块：这些模块实现了特定的应用程序/业务功能，如博客、文档管理、身份管理、租户管理…等等。
                                           
                                           它们通常有自己的实体、服务、API和UI组件。请参阅预构建的应用程序模块。

                                                                        
                    */
        </script>
    </body>
</html>